1
2
3
4 package joeq.Debugger;
5
6 import java.util.StringTokenizer;
7 import java.io.BufferedReader;
8 import java.io.IOException;
9 import java.io.InputStreamReader;
10 import joeq.Allocator.CodeAllocator;
11 import joeq.Class.jq_Array;
12 import joeq.Class.jq_Class;
13 import joeq.Class.jq_CompiledCode;
14 import joeq.Class.jq_InstanceField;
15 import joeq.Class.jq_LocalVarTableEntry;
16 import joeq.Class.jq_Method;
17 import joeq.Class.jq_Primitive;
18 import joeq.Class.jq_Reference;
19 import joeq.Compiler.CompilationState;
20 import joeq.Compiler.BytecodeAnalysis.BytecodeVisitor;
21 import joeq.Main.TraceFlags;
22 import joeq.Main.jq;
23 import joeq.Memory.Address;
24 import joeq.Memory.CodeAddress;
25 import joeq.Memory.HeapAddress;
26 import joeq.Memory.StackAddress;
27 import joeq.Runtime.Debug;
28 import joeq.Runtime.Reflection;
29 import joeq.Runtime.StackCodeWalker;
30 import joeq.Runtime.SystemInterface;
31 import joeq.Scheduler.jq_NativeThread;
32 import jwutil.strings.Strings;
33 import jwutil.util.Assert;
34
35 /***
36 * @author John Whaley <jwhaley@alum.mit.edu>
37 * @version $Id: OnlineDebugger.java 1941 2004-09-30 03:37:06Z joewhaley $
38 */
39 public class OnlineDebugger {
40
41 public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
42
43 static boolean inDebugger;
44
45 public static boolean debuggerEntryPoint() {
46 if (!jq.RunningNative) {
47 new InternalError().printStackTrace();
48 System.exit(-1);
49 }
50 if (inDebugger) {
51 SystemInterface.debugwriteln("Recursively entering debugger!");
52 StackAddress fp = StackAddress.getBasePointer();
53 CodeAddress ip = (CodeAddress) fp.offset(4).peek();
54 Debug.writeln("fp = ", fp);
55 Debug.writeln("ip = ", ip);
56 return false;
57 }
58 inDebugger = true;
59 SystemInterface.debugwriteln(">>> Entering debugger.");
60 StackAddress fp = StackAddress.getBasePointer();
61 CodeAddress ip = (CodeAddress) fp.offset(4).peek();
62 fp = (StackAddress) fp.peek();
63 StackCodeWalker sw = new StackCodeWalker(ip, fp);
64 int frameNum = 0;
65 SystemInterface.debugwriteln("> "+frameNum+":"+sw.toString());
66
67
68 uphere:
69 for (;;) {
70 SystemInterface.debugwrite("db> ");
71 String s = null;
72 try {
73 s = in.readLine();
74 } catch (IOException _) { }
75 if (s == null) {
76 SystemInterface.debugwriteln(">>> Exiting debugger.");
77 inDebugger = false;
78 return true;
79 }
80 if (s.equals("")) {
81 continue;
82 }
83 if (s.equals("c")) {
84 SystemInterface.debugwriteln(">>> Continuing execution.");
85 inDebugger = false;
86 return true;
87 }
88 if (s.equals("s")) {
89 SystemInterface.debugwriteln("Single-step not yet implemented.");
90 continue;
91 }
92 if (s.equals("u")) {
93 if (!sw.hasNext()) {
94 SystemInterface.debugwriteln("Reached top.");
95 continue;
96 }
97 sw.gotoNext(); ++frameNum;
98 SystemInterface.debugwriteln("> "+frameNum+":"+sw.toString());
99 continue;
100 }
101 if (s.equals("d")) {
102 if (frameNum == 0) {
103 SystemInterface.debugwriteln("Reached top.");
104 continue;
105 }
106 StackCodeWalker sw2 = new StackCodeWalker(ip, fp);
107 for (;;) {
108 if (!sw2.hasNext()) {
109 SystemInterface.debugwriteln("ERROR! Stack is corrupted.");
110 continue uphere;
111 }
112 if (sw2.getFP().peek().difference(sw.getFP()) == 0)
113 break;
114 sw2.gotoNext();
115 }
116 sw = sw2; --frameNum;
117 SystemInterface.debugwriteln("> "+frameNum+":"+sw.toString());
118 continue;
119 }
120 if (s.equals("bt")) {
121 StackCodeWalker sw2 = new StackCodeWalker(ip, fp);
122 int counter = 0;
123 while (sw2.hasNext()) {
124 if (counter == frameNum) {
125 SystemInterface.debugwriteln("> "+counter+":"+sw2.toString());
126 if (sw2.getFP().difference(sw.getFP()) != 0) {
127 SystemInterface.debugwriteln("ERROR! Stack is corrupted. Expected "+sw+" but found "+sw2);
128 }
129 } else {
130 SystemInterface.debugwriteln(" "+counter+":"+sw2.toString());
131 }
132 sw2.gotoNext(); ++counter;
133 }
134 continue;
135 }
136 if (s.equals("t")) {
137 jq_NativeThread.dumpAllThreads();
138 continue;
139 }
140 if (s.equals("sf")) {
141 printStackFrame(sw);
142 continue;
143 }
144 if (s.equals("l")) {
145 jq_Method m = sw.getMethod();
146 if (m == null) {
147 SystemInterface.debugwriteln("Unknown method!");
148 continue;
149 }
150 if (m.getBytecode() == null) {
151 SystemInterface.debugwriteln("No bytecode for method "+m+"!");
152 continue;
153 }
154 int currentIndex = sw.getBCIndex();
155 if (currentIndex < 0) currentIndex = 0;
156 BytecodeLister bl = new BytecodeLister(m, 0, m.getBytecode().length, currentIndex);
157 bl.forwardTraversal();
158 continue;
159 }
160 if (s.equals("?")) {
161 printUsage();
162 continue;
163 }
164 if (s.startsWith("toString ")) {
165 s = s.substring(9);
166 if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2);
167 int k = (int) Long.parseLong(s, 16);
168 HeapAddress addr = HeapAddress.address32(k);
169 Object o = addr.asObject();
170 SystemInterface.debugwriteln(o.toString());
171 continue;
172 }
173 if (s.startsWith("dumpObject ")) {
174 s = s.substring(11);
175 if (s.startsWith("0x") || s.startsWith("0X")) s = s.substring(2);
176 int k = (int) Long.parseLong(s, 16);
177 dumpObject(k);
178 continue;
179 }
180
181 String[] commands;
182 StringTokenizer st = new StringTokenizer(s);
183 int size = st.countTokens();
184 commands = new String[size];
185 for (int j = 0; j < size; ++j) {
186 commands[j] = st.nextToken();
187 }
188 Assert._assert(!st.hasMoreTokens());
189 int index2 = TraceFlags.setTraceFlag(commands, 0);
190 if (0 != index2) {
191 continue;
192 }
193
194
195
196
197
198
199
200
201
202
203 }
204 }
205
206 public static void printUsage() {
207 SystemInterface.debugwriteln("c: continue, s: step");
208 SystemInterface.debugwriteln("l: list bytecode");
209 SystemInterface.debugwriteln("dumpObject, toString");
210 SystemInterface.debugwriteln("u: up, d: down, sf: stack frame, bt: back trace, t: thread dump");
211 }
212
213 public static void dumpObject(int k) {
214 HeapAddress addr = HeapAddress.address32(k);
215 Object o = addr.asObject();
216 dumpObject(o);
217 }
218
219 public static void dumpObject(Object o) {
220 HeapAddress addr = HeapAddress.addressOf(o);
221 jq_Reference t = jq_Reference.getTypeOf(o);
222 SystemInterface.debugwriteln(addr.stringRep()+" type "+t);
223 if (t.isClassType()) {
224 jq_Class c = (jq_Class) t;
225 jq_InstanceField[] f = c.getInstanceFields();
226 for (int j=0; j<f.length; ++j) {
227 StringBuffer sb = new StringBuffer();
228 sb.append(Strings.left(f[j].getName().toString(), 15));
229 sb.append(':');
230 if (f[j].getType().isReferenceType()) {
231 Address addr2 = addr.offset(f[j].getOffset()).peek();
232 sb.append(addr2.stringRep());
233 } else {
234 sb.append(Reflection.getfield(o, f[j]));
235 }
236 SystemInterface.debugwriteln(sb.toString());
237 }
238 } else {
239 jq_Array a = (jq_Array) t;
240 int length = Reflection.arraylength(o);
241 for (int j=0; j<length; ++j) {
242 if (a.getElementType().isReferenceType()) {
243 SystemInterface.debugwriteln(j+": "+addr.offset(j*HeapAddress.size()).peek().stringRep());
244 } else if (a.getElementType() == jq_Primitive.FLOAT) {
245 SystemInterface.debugwriteln(j+": "+Float.intBitsToFloat(addr.offset(j*4).peek4()));
246 } else if (a.getElementType() == jq_Primitive.DOUBLE) {
247 SystemInterface.debugwriteln(j+": "+Double.longBitsToDouble(addr.offset(j*8).peek8()));
248 } else if (a.getElementType().getReferenceSize() == 1) {
249 SystemInterface.debugwriteln(j+": "+addr.offset(j).peek1());
250 } else if (a.getElementType().getReferenceSize() == 2) {
251 SystemInterface.debugwriteln(j+": "+addr.offset(j*2).peek2());
252 } else if (a.getElementType().getReferenceSize() == 4) {
253 SystemInterface.debugwriteln(j+": "+addr.offset(j*4).peek4());
254 } else if (a.getElementType().getReferenceSize() == 8) {
255 SystemInterface.debugwriteln(j+": "+addr.offset(j*8).peek8());
256 }
257 }
258 }
259 }
260
261 public static void printStackFrame(StackCodeWalker sw) {
262 StackAddress my_fp = sw.getFP();
263 if (my_fp.isNull()) {
264 SystemInterface.debugwriteln("Cannot dump this frame!"+Strings.lineSep);
265 return;
266 }
267 CodeAddress my_ip = (CodeAddress) my_fp.offset(4).peek();
268 StackAddress next_fp = (StackAddress) my_fp.peek();
269 if (my_fp.isNull()) {
270 SystemInterface.debugwriteln("Cannot dump this frame!"+Strings.lineSep);
271 return;
272 }
273 jq_CompiledCode cc = CodeAllocator.getCodeContaining(my_ip);
274 jq_Method m = null;
275 if (cc != null) m = cc.getMethod();
276 SystemInterface.debugwriteln("Stack frame for "+cc);
277 if (m != null) {
278 SystemInterface.debugwriteln(((int)m.getMaxLocals())+" locals, "+((int)m.getParamWords())+" param words");
279 }
280
281
282
283
284
285
286
287
288
289 StackAddress ptr = my_fp;
290 int framesize = 0;
291 if (m != null) framesize = (m.getParamWords()+1)*StackAddress.size();
292 while (ptr.difference(next_fp) <= framesize) {
293 if (ptr.difference(my_fp) == 0) {
294 SystemInterface.debugwriteln("Callee FP: "+ptr.stringRep()+" : "+ptr.peek().stringRep());
295 } else if (ptr.difference(next_fp) == StackAddress.size()) {
296 CodeAddress my_ip2 = (CodeAddress) ptr.peek();
297 jq_CompiledCode cc2 = CodeAllocator.getCodeContaining(my_ip2);
298 int code_offset = 0;
299 if (cc2 != null)
300 code_offset = my_ip2.difference(cc2.getStart());
301 SystemInterface.debugwriteln("Caller retaddr: "+ptr.stringRep()+" : "+ptr.peek().stringRep()+" (offset "+Strings.hex(code_offset)+")");
302 } else if (m != null && ptr.difference(next_fp) > 0) {
303 int n = m.getParamWords() - ptr.difference(next_fp) / StackAddress.size() + 1;
304 SystemInterface.debugwriteln(Strings.left("Incoming arg "+n+":", 16)+ptr.stringRep()+" : "+ptr.peek().stringRep());
305 } else if (ptr.difference(my_fp) == StackAddress.size()) {
306 int code_offset = 0;
307 if (cc != null)
308 code_offset = my_ip.difference(cc.getStart());
309 SystemInterface.debugwriteln("Return address: "+ptr.stringRep()+" : "+ptr.peek().stringRep()+" (offset "+Strings.hex(code_offset)+")");
310 } else if (next_fp.difference(ptr) == 0) {
311 SystemInterface.debugwriteln("Caller FP: "+ptr.stringRep()+" : "+ptr.peek().stringRep());
312 } else if (m != null && next_fp.difference(ptr) <= StackAddress.size()*(m.getMaxLocals()-m.getParamWords())) {
313 int n = next_fp.difference(ptr) / StackAddress.size() - 1;
314 int offset = sw.getBCIndex();
315 jq_LocalVarTableEntry e = m.getLocalVarTableEntry(offset, n);
316 String nd = (e != null) ? e.getNameAndDesc().toString() : "";
317 SystemInterface.debugwriteln(Strings.left("Local "+n+": ", 16)+ptr.stringRep()+" : "+ptr.peek().stringRep()+"\t"+nd);
318 } else if (m != null && ptr.difference(my_fp) > StackAddress.size()) {
319 int n = next_fp.difference(ptr) / StackAddress.size() - m.getMaxLocals() + m.getParamWords() - 2;
320 SystemInterface.debugwriteln(Strings.left("Stack "+n+": ", 16)+ptr.stringRep()+" : "+ptr.peek().stringRep());
321 } else {
322 SystemInterface.debugwriteln(" "+ptr.stringRep()+" : "+ptr.peek().stringRep());
323 }
324 ptr = (StackAddress) ptr.offset(StackAddress.size());
325 }
326 }
327
328 public static class BytecodeLister extends BytecodeVisitor {
329
330 protected int i_loc;
331 protected int i_stop;
332
333 public BytecodeLister(jq_Method m, int start, int stop, int loc) {
334 super(CompilationState.DEFAULT, m);
335 this.i_end = start-1;
336 this.i_start = start;
337 this.i_stop = stop;
338 this.i_loc = loc;
339 this.out = System.err;
340 this.TRACE = true;
341 }
342 public void forwardTraversal() throws VerifyError {
343 for (i_end=-1; ; ) {
344 i_start = i_end+1;
345 if (i_start == i_loc) {
346 out.println("Current location:");
347 }
348 if (i_start >= i_stop) break;
349 this.visitBytecode();
350 }
351 }
352 public String toString() { return Strings.left(method.getName().toString(), 12); }
353 }
354
355 }